package redis

type ListDirection byte

const (
	ListLeft ListDirection = iota + 1
	ListRight
)

func dirString(dir ListDirection) string {
	switch dir {
	case ListLeft:
		return "LEFT"
	case ListRight:
		return "RIGHT"
	}
	return ""
}

func (k *key) LPush(value ...any) IntResult {
	args := []any{k.key}
	for _, v := range value {
		args = append(args, v)
	}
	return k.cmd("LPUSH", args...)
}

func (k *key) LPushX(value any) IntResult {
	return k.cmd("LPUSHX", k.key, value)
}

func (k *key) RPush(value ...any) IntResult {
	args := []any{k.key}
	for _, v := range value {
		args = append(args, v)
	}
	return k.cmd("RPUSH", args...)
}

func (k *key) RPushX(value any) IntResult {
	return k.cmd("RPUSHX", k.key, value)
}

func (k *key) LPop() ValueResult {
	return k.cmd("LPOP", k.key)
}

func (k *key) RPop() ValueResult {
	return k.cmd("RPOP", k.key)
}

// func (k *key) RPopLPush(destKey string) ValueResult {
// 	return k.cmd("RPOPLPUSH", k.key, destKey)
// }

func (k *key) LRem(count int, value any) IntResult {
	return k.cmd("LREM", k.key, count, value)
}

func (k *key) LLen() IntResult {
	return k.cmd("LLEN", k.key)
}

func (k *key) LIndex(index int) ValueResult {
	return k.cmd("LINDEX", k.key, index)
}

func (k *key) LInsertBefore(pivot, value any) IntResult {
	return k.cmd("LINSERT", k.key, "BEFORE", pivot, value)
}

func (k *key) LInsertAfter(pivot, value any) IntResult {
	return k.cmd("LINSERT", k.key, "AFTER", pivot, value)
}

func (k *key) LSet(index int, value any) BoolResult {
	return k.cmd("LSET", k.key, index, value)
}

func (k *key) LRange(start, stop int) ListResult {
	return k.cmd("LRANGE", k.key, start, stop)
}

func (k *key) LTrim(start, stop int) ListResult {
	return k.cmd("LTRIM", k.key, start, stop)
}

func (k *key) BLPop(timeout int) ListResult {
	var args []any
	for _, k := range k.keys {
		args = append(args, k)
	}
	args = append(args, timeout)
	return k.cmd("BLPOP", args...)
}

func (k *key) BRPop(timeout int) ListResult {
	var args []any
	for _, k := range k.keys {
		args = append(args, k)
	}
	args = append(args, timeout)
	return k.cmd("BRPOP", args...)
}

// func (k *key) BRPopLPush(destKey string, timeout int) ValueResult {
// 	return k.cmd("BRPOPLPUSH", k.key, destKey, timeout)
// }

func (k *key) LMove(srcDir, dstDir ListDirection) ValueResult {
	args := []any{k.key}
	if len(k.keys) < 2 {
		args = append(args, k.key)
	} else {
		args = append(args, k.keys[1])
	}
	args = append(args, dirString(srcDir), dirString(dstDir))
	return k.cmd("LMOVE", args...)
}

func (k *key) BLMove(srcDir, dstDir ListDirection, timeout int) ValueResult {
	args := []any{k.key}
	if len(k.keys) < 2 {
		args = append(args, k.key)
	} else {
		args = append(args, k.keys[1])
	}
	args = append(args, dirString(srcDir), dirString(dstDir), timeout)
	return k.cmd("BLMOVE", args...)
}

/*
func (k *key) LMPop(dir ListDirection, count int) ValueResult {
	if count < 1 {
		count = 1
	}
	args := []any{len(k.keys)}
	for _, kk := range k.keys {
		args = append(args, kk)
	}
	args = append(args, dirString(dir), count)
	return k.cmd("LMPOP", args...)
}

func (k *key) BLMPop(timeout int, dir ListDirection, count int) ValueResult {
	if count < 1 {
		count = 1
	}
	args := []any{timeout, len(k.keys)}
	for _, kk := range k.keys {
		args = append(args, kk)
	}
	args = append(args, dirString(dir), count)
	return k.cmd("BLMPOP", args...)
}
*/

type LPosArgs struct {
	Rank   int
	MaxLen int
}

func (k *key) LPos(elem any, ex *LPosArgs) ValueResult {
	args := []any{elem}
	if ex != nil {
		if ex.Rank > 0 {
			args = append(args, "RANK", ex.Rank)
		}
		if ex.MaxLen > 0 {
			args = append(args, "MAXLEN", ex.MaxLen)
		}
	}
	return k.cmd("LPOS", args...)
}

func (k *key) LPosCount(elem any, cnt int, ex *LPosArgs) ListResult {
	args := []any{elem, "COUNT", cnt}
	if ex != nil {
		if ex.Rank > 0 {
			args = append(args, "RANK", ex.Rank)
		}
		if ex.MaxLen > 0 {
			args = append(args, "MAXLEN", ex.MaxLen)
		}
	}
	return k.cmd("LPOS", args...)
}
